<?php
/**
 * <pre>
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT      : rubik-base
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * [GENERAL INFO OF THIS FILE] 
 *
 * </pre>
 * 
 * @version 		1.5
 * @author			hoadn <hoadn@rubik.com.vn>
 * @access			public
 * @package			rubik.base.dbo
 *
 * Created on	: May 7, 2008
 */
RCoreImporter::cls("helper.RStringHelper" );

/* Basic DATA TYPE */
define ( "SYM_TYPE_STRING", "S" );
define ( "SYM_TYPE_NUMBER", "N" );
define ( "SYM_TYPE_FLOAT", "F" );
define ( "SYM_TYPE_DATE", "D" );
define ( "SYM_TYPE_TIME_NUMBER", "TN" );
define ( "SYM_TYPE_DATETIME", "DT" );
define ( "SYM_TYPE_TIME", "T" );
define ( "SYM_TYPE_TIMESTAMP", "TS" );
define ( "SYM_TYPE_BOOLEAN", "B" );

/**
 * String that is build from server not submited by client! 
 * We use this type of string for special treat when add slash or not. 
 *
 */
define ( "SYM_TYPE_STRING_BUILD", "SB" ); 

/**
 * The string MD5 data type!
 * We use this data type for determind and convert the string into MD5 
 * before stored or compare with database
 *
 */
define ( "SYM_TYPE_MD5", "MD5" );

define ( "SYM_TYPE_EMAIL", "EM" );
define ( "SYM_TYPE_TEXT", "TX" );

/* Basic Symbol */
/**
 * NOW is using in Default value section for the data type Date.
 * It let the system know that the Date, time default is current
 *
 */
define ( "SYM_CURRENT_TIME", "NOW" );

/**
 * UNIQUE is used in Data define section for let the system know this field is UNIQUE.
 *
 */
define ( "SYM_UNIQUE", "&u" );

/**
 * MANDATORY is used in Data define section for let the system know this field is MANDATORY.
 *
 */
define ( "SYM_MANDATORY", "*" );

/**
 * KEY is used in Key (4th) section for let the system know this field is KEY.
 *
 */
define ( "SYM_KEY", "key" );

class RubikDBField {
	var $fieldName;
	var $dataType = SYM_TYPE_STRING;
	var $defaultValue = null;
	var $alias;
	var $isKey = false;
	var $isMandatory = false;
	var $isUnique = false;
	var $dbRealName;
	var $maxLength;
	
	/**
	 * Constructor
	 *
	 * @param string $fieldName
	 * @param string $infoString format: <data type>[‘*’]|[<default value>]|[<alias>]|[‘key’]
	 */
	function RubikDBField($fieldName, $infoString = '') {
		$this->fieldName = $fieldName;
		$this->dbRealName = $fieldName;
		$this->_parse ( $infoString );
	}
	
	/**
	 * parse the information of the field
	 *
	 * @param string $infoString format: <data type>[‘*’]|[<default value>]|[<alias>]|[‘key’]
	 * @access protected
	 */
	function _parse($infoString) {
		$arrInfo = explode ( "|", $infoString );
		
		if (strpos ( $arrInfo [0], SYM_MANDATORY ) !== false) {
			$this->isMandatory = true;
			$arrInfo [0] = str_replace ( SYM_MANDATORY, "", $arrInfo [0] );
		}
		if (strpos ( $arrInfo [0], SYM_UNIQUE ) !== false) {
			$this->isUnique = true;
			$arrInfo [0] = str_replace ( SYM_UNIQUE, "", $arrInfo [0] );
		}
		$this->maxLength = intval($arrInfo[0]);
		$arrInfo [0] = str_replace ( $this->maxLength, "", $arrInfo [0] );
		$this->dataType = $arrInfo [0];
		
		if (! RStringHelper::isEmpty ( $arrInfo [1] )) {
			$this->defaultValue = $arrInfo [1];
		}
		$this->alias = $arrInfo [2];
		
		$arrInfo [3] = strtolower ( $arrInfo [3] );
		if (strpos ( $arrInfo [3], SYM_KEY ) !== false) {
			$this->isKey = true;
			$this->isMandatory = true;
		} else if (! empty ( $arrInfo [3] )) {
			$this->dbRealName = $arrInfo [3];
		}
	}
	
	/**
	 * Check if this field has datatype in: Date, DateTime, Time
	 *
	 * @return boolean 
	 */
	function isDate() {
		if ($this->dataType == SYM_TYPE_DATE || $this->dataType == SYM_TYPE_DATETIME 
			|| $this->dataType == SYM_TYPE_TIME || $this->dataType == SYM_TYPE_TIMESTAMP 
			|| $this->dataType == SYM_TYPE_TIME_NUMBER) {
			return true;
		}
		return false;
	}
	
	/**
	 * Check if this field has datatype in: Number, Float
	 *
	 * @return boolean 
	 */
	function isNumeric() {
		if ($this->dataType == SYM_TYPE_NUMBER || $this->dataType == SYM_TYPE_FLOAT) {
			return true;
		}
		return false;
	}
	
	/**
	 * Check if this field has datatype is: Boolean 
	 *
	 * @return boolean 
	 */
	function isBoolean() {
		if ($this->dataType == SYM_TYPE_BOOLEAN) {
			return true;
		}
		return false;
	}
	
	/**
	 * Check if this field has datatype is: String 
	 *
	 * @return boolean 
	 */
	function isString() {
		if ($this->isBoolean() || $this->isDate() || $this->isNumeric()) {
			return false;
		}
		return true;
	}
	
	/**
	 * Get the field name with aliase
	 * 
	 * @param RubikDBInfo $dbInfo this is using for adding quote for database field
	 *
	 * @return string
	 */
	function getNameWithAlias($dbInfo = null, $inludeFieldAlias = false) {
		if ($dbInfo == null) {
			$fieldName = $this->fieldName;
			$alias = $this->alias;
			$dbRealName = $this->dbRealName;
		} else {
			$fieldName = $dbInfo->dbQuoteField ( $this->fieldName );
			$alias = $dbInfo->dbQuoteField ( $this->alias );
			if (strpos ( $this->dbRealName, "(" ) !== false && strpos ( $this->dbRealName, ")" ) !== false) {
				$dbRealName = $this->dbRealName;
			} else {
				$dbRealName = $dbInfo->dbQuoteField ( $this->dbRealName );
			}
		}
		
		if ($inludeFieldAlias) {
			// add quote
			return (empty ( $this->alias ) ? $dbRealName : "$alias.$dbRealName") . " $fieldName";
		}
		
		// add quote
		return empty ( $this->alias ) ? $dbRealName : "$alias.$dbRealName";
	}
	
	/**
	 * Preparing data before saving it into database.
	 * This step help do some generic and reduce problem of SQL injection
	 *
	 * @param AbstractRubikDBObject $rubikDBO
	 */
	function prepareDataForDB(&$rubikDBO) {
		return $this->_prepareData ( $rubikDBO, "db" );
	}
	
	/**
	 * Preparing data before saving it into database.
	 * This step help do some generic and reduce problem of SQL injection
	 *
	 * @param AbstractRubikDBObject $rubikDBO
	 */
	function prepareDataForView(&$rubikDBO) {
		return $this->_prepareData ( $rubikDBO, "view" );
	}
	
	/**
	 * Preparing data before saving it into database.
	 * This step help do some generic and reduce problem of SQL injection
	 *
	 * @param AbstractRubikDBObject $rubikDBO
	 */
	function _prepareData(&$rubikDBO, $type) {
		$fieldName = $this->fieldName;
		if (is_object ( $rubikDBO )) {
			$val = &$rubikDBO->$fieldName;
		} else {
			$val = &$rubikDBO;
		}
		if ($val !== null) {
			//			if (RStringHelper::isEmpty($val)) {
			//				$val = null;
			//				return $val;
			//			}
			

			if ($this->dataType == SYM_TYPE_NUMBER) {
				$val = RStringHelper::isEmpty($val) ? null : intval ( $val );
			} else if ($this->dataType == SYM_TYPE_FLOAT) {
				$val = RStringHelper::isEmpty($val) ? null : doubleval ( $val );
			} else if ($this->dataType == SYM_TYPE_MD5) {
				$val = md5($val);
			} else if ($this->isBoolean ()) {
				if (RStringHelper::isEmpty($val)) {
					$val = null;
				}
				else {
					$val = intval ( $val ) ? 1 : 0;
				}
//			} else if ($this->isDate ()) {
//				if (is_object ( $rubikDBO )) {
//					$dbInfo = RubikDBFactory::getDBInfo ( $rubikDBO );
//					if ($type == "view") {
//						$val = $dbInfo->convertDateDbToView ( $val, $this->dataType );
//					} else {
//						$val = $dbInfo->convertDateViewToDb ( $val, $this->dataType );
//					}
//				}
			} else if ($this->dataType == SYM_TYPE_TIME_NUMBER) {
				if (! is_numeric ( $val ) && $rubikDBO) {
					$dbInfo = RubikDBFactory::getDBInfo ( $rubikDBO );
					if ($type == "view") {
						$val = $dbInfo->convertDateDbToView ( $val, $this->dataType );
					} else {
						$val = $dbInfo->convertDateViewToDb ( $val, $this->dataType );
					}
				}
			} else if ($this->dataType == SYM_TYPE_STRING_BUILD) {
				if ($type = 'db' && get_magic_quotes_gpc ()) {
					$val = addslashes($val);
				}
			}
		}
		return $val;
	}

}
?>